using System.Collections;

namespace Slaks.Graphs.Algorithms
{
	/// <summary>
	/// Lee Navaro Shepard (An empirical evaluation of models of text document similarity)
	/// </summary>
	public class DistCommonFeaturesModel : GraphDistanceBase
	{
        public DistCommonFeaturesModel() : base ()
        {
        }

        public DistCommonFeaturesModel(Graph one, Graph two) 
            : base ( one, two )
        {
        }

		private double calcDistance()
		{
			VertexList oneList = one.GetVertexList();
			VertexList twoList = two.GetVertexList();

			double common = 0;
			double missingOne = 0;
			double missingTwo = 0;
			double different = 0; //different direction of the edge

			#region find vertices

			Graph testGraphOne, testGraphTwo;
			if (one.GetVertexCount() > two.GetVertexCount())
			{
				testGraphOne = one;
				testGraphTwo = two;
			}
			else
			{
				testGraphOne = two;
				testGraphTwo = one;
			}
			foreach (Vertex vertex in testGraphOne.GetVertexList())
			{
				if (testGraphTwo.GetVertex(vertex.GetId()) == null) missingOne += 1;
				else common += 1;
			}

			#endregion

			#region find edges

			Vertex vertexOne;
			Vertex vertexTwo;

			Vertex vertexOneNext;
			Vertex vertexTwoNext;

			long id;
			long nextId;
			IDictionary sectionsOne, sectionsTwo;
			for (int i = 0; i < oneList.Count; i++)
			{
				id = oneList[i].GetId();
				vertexOne = one.GetVertex(id);

				vertexTwo = two.GetVertex(id);
				if (vertexTwo == null) continue;

				for (int j = i; j < oneList.Count; j++)
				{
					nextId = oneList[j].GetId();
					sectionsOne = vertexOne.GetSectionsIfConnected(nextId);
					sectionsTwo = vertexTwo.GetSectionsIfConnected(nextId);

					ICollection sectionsOneKeys = sectionsOne.Keys;

					foreach (string section in sectionsOneKeys)
					{
						if (sectionsTwo.Contains(section))
						{
							common += 1;
						}
						else missingTwo += 1;
					}

					if (id == nextId) continue;
					vertexOneNext = one.GetVertex(nextId);
					vertexTwoNext = two.GetVertex(nextId);

					if (vertexTwoNext == null) continue;

					sectionsOne = vertexOneNext.GetSectionsIfConnected(id);
					sectionsTwo = vertexTwoNext.GetSectionsIfConnected(id);

					sectionsOneKeys = sectionsOne.Keys;
					foreach (string section in sectionsOneKeys)
					{
						if (sectionsTwo.Contains(section))
						{
							common += 1;
						}
						else missingTwo += 1;
					}

				} //end of for
			}

			#endregion

			#region find edges 2

			for (int i = 0; i < twoList.Count; i++)
			{
				id = twoList[i].GetId();
				vertexOne = one.GetVertex(id);
				vertexTwo = two.GetVertex(id);

				if (vertexOne == null) continue;
				for (int j = i; j < twoList.Count; j++)
				{
					nextId = twoList[j].GetId();
					sectionsOne = vertexOne.GetSectionsIfConnected(nextId);
					sectionsTwo = vertexTwo.GetSectionsIfConnected(nextId);

					ICollection sectionsTwoKeys = sectionsTwo.Keys;

					foreach (string section in sectionsTwoKeys)
					{
						if (sectionsOne.Contains(section))
						{
						}
						else missingOne += 1;
					}

					if (id == nextId) continue;
					vertexOneNext = one.GetVertex(nextId);
					vertexTwoNext = two.GetVertex(nextId);

					if (vertexOneNext == null) continue;

					sectionsOne = vertexOneNext.GetSectionsIfConnected(id);
					sectionsTwo = vertexTwoNext.GetSectionsIfConnected(id);

					sectionsTwoKeys = sectionsTwo.Keys;
					foreach (string section in sectionsTwoKeys)
					{
						if (sectionsOne.Contains(section))
						{
						}
						else missingOne += 1;
					}

				} //end of for
			}

			#endregion

			double result = common/(missingOne + missingTwo + common + different);
			return result;
		}

        public override double GetDistance()
        {
            double commonFeatureModel = calcDistance();
            if (commonFeatureModel == 0.0) return 1;
            return 1 - commonFeatureModel;
        }
	}
}